﻿clear;
function Main([array]$ar)
{
	$argumentError = $false;

	$header = "DNS Migration Toolkit
	Programmed by Fatih Tolga Ata (c) 2012";

	if (($ar.Length -gt 0) -and 
		($ar[0] -ne "backup") -and 
		($ar[0] -ne "restore"))
	{
		echo $header;
		Write-Error "You must give a valid command.";
		$argumentError = $true;
	}

	if ($ar.Length -eq 0) 
	{
		echo $header;
	}

	if ($ar.Length -eq 0 -or $argumentError)
	{
		echo "
		Usage: DnsMigrate.ps1 [command] [options]
			commands:
				backup		: Backup all records to specific location
				restore		: Restore from specific location
			
			backup options:
				[path]		: Backup output file location.
			restore options:
				[path]		: The backup file that will be restored.
				-overwrite	: Overwrites all zones and records if exists.
				-skipzone	: Skips zone if exists.
				-skiprecord	: Skips records if exits.
				-test		: Only shows which will be removed/created. Prevents to remove and create existing data.
			
			example: DnsMigrate.ps1 backup `"C:\dnsbackup.bak`"
		";
	}

	if($ar[0] -eq "backup")
	{
		Backup -path $ar[1];
	}
	if($ar[0] -eq "restore")
	{
		$path = "";
		$overwrite = $false;
		$skipzone = $false;
		$skiprecord = $false;
		$test = $false;
		for($i = 1; $i -lt $ar.Length; $i++)
		{
			if ($ar[$i] -eq "-overwrite")
			{
				$overwrite = $true;
				continue;
			}
			elseif ($ar[$i] -eq "-skipzone")
			{
				$skipzone = $true;
				continue;			
			}
			elseif ($ar[$i] -eq "-skiprecord")
			{
				$skiprecord = $true;
				continue;
			}
			elseif ($ar[$i] -eq "-test")
			{
				$test = $true;
				continue;
			}
			else
			{
				$path = $ar[$i];
			}
		}
		Restore -path $path -overwrite $overwrite -skipzone $skipzone -skiprecord $skiprecord -test $test;
	}
}

function Backup([string] $path)
{
	try
	{
		$query = "SELECT * FROM MicrosoftDNS_ResourceRecord";
		$records = Get-WmiObject `
			-Namespace root\MicrosoftDNS `
			-Query $query;
		
		Export-Clixml -InputObject $records -Path $path;
	}
	catch [Exception]
	{
		Write-Error $error[0];
		return;
	}
	[string]::Format("{0} record(s) was backed up sucessfully.", $records.Count);
}

function Restore([string]$path, [boolean]$overwrite, 
	[boolean]$skipzone, [boolean]$skiprecord, [boolean]$test)
{
	if (-not (Test-Path $path))
	{
		Write-Error ([string]::Format("{0} is not exists", $path));
		return;
	}
	
	$records = (Import-Clixml -Path $path) | 
		where {
			$_.ContainerName -notcontains "..Cache" -and 
			$_.ContainerName -notcontains "..RootHints" -and
			$_.ContainerName -notcontains "TrustAnchors" -and
			$_.ContainerName -notmatch ".in-addr.arpa"
		};
	
	#zone listesini alalım.
	$zones = $records | select ContainerName -unique;
	
	#mevcut zone'ları alalım.
	$query = "SELECT * FROM MicrosoftDNS_Zone";
	$currentZones = Get-WmiObject `
		-Namespace root\MicrosoftDNS `
		-Query $query;
		
	#mevcut record'ları alalım.
	$query = "SELECT * FROM MicrosoftDNS_ResourceRecord";
	$currentRecords = Get-WmiObject `
		-Namespace root\MicrosoftDNS `
		-Query $query;
		
	#zone'ları oluşturulaım.
	foreach ($zone in $zones)
	{	
		$c = $currentZones | where {$_.Name -eq $zone.ContainerName};
		if ($c -ne $null -and $c -ne "")
		{
			if ($overwrite)
			{
				if (-not $test)
				{
					$currentZones | where {$_.Name -eq $zone.ContainerName} | Remove-WmiObject;
				}
				echo ([string]::Format("info: removed {0}",$c.Name));
			}
		}
		else
		{
			if (-not $test)
			{
				$newZone = ([wmiclass]"\\localhost\root\MicrosoftDNS:MicrosoftDNS_Zone").CreateZone($zone.ContainerName, 0);
			}
			echo ([string]::Format("info: zone created, {0}",$zone.ContainerName));
		}
	}
	
	$mxRecords = $records | where {$_.__CLASS -eq "MicrosoftDNS_MXType"};
	$otherRecords = $records | where {$_.__CLASS -ne "MicrosoftDNS_MXType"};

	foreach($record in $records)
	{
		$currentZone = $currentZones | where {$_.Name -eq $record.ContainerName};
		if ($currentZone -ne $null -and $currentZone -ne "" -and $skipzone)
		{
			continue;
		}
		
		#bu record mevcut kayıtlarda var mı?	
		$currentRecord = $currentRecords | where {
				[string]$_.OwnerName -contains [string]$record.OwnerName -and
				[string]$_.__CLASS -contains [string]$record.__CLASS -and
				$_.Preference -eq $record.Preference
			};

		if ($currentRecord -ne $null -and $currentRecord -ne "")
		{
			#We will allow only multiple NS records. Others must be unique by OwnerName,Class,Preference(MX)
			if ($skiprecord -or $currentRecord.__CLASS -match "NSType")
			{
				continue;
			}
			if (-not $test)
			{
				Remove-WmiObject $currentRecord;
			}
			echo ([string]::Format("info: record removed, {0}",$currentRecord.TextRepresentation))
		}
		
		$recordClassString = "\\localhost\root\MicrosoftDNS:MicrosoftDNS_ResourceRecord";
		$newRecordClass = [wmiclass]$recordClassString;

		try
		{
			if (-not $test)
			{
				$newRecord = $newRecordClass.CreateInstanceFromTextRepresentation(
					"localhost", $record.ContainerName, $record.TextRepresentation);
			}
		}
		catch [Exception]
		{
			Write-Error $errors[0].Message;
			return;
		}
		
		echo ([string]::Format("info: record created, {0}", $record.TextRepresentation));
	}
	
	echo "Don't forget to update server data files from DNS Manager";
}

Main($args);